package kr.co.insoft.core.service.orchestration.impl;

import kr.co.insoft.auth.model.security.User;
import kr.co.insoft.core.model.configration.sev.SEVEntityModel;
import kr.co.insoft.core.model.orchestration.CompositeEntityModel;
import kr.co.insoft.core.model.orchestration.CompositeStackEntityModel;
import kr.co.insoft.core.model.orchestration.OrchestrationResultModel;
import kr.co.insoft.core.model.orchestration.ProjectEntityModel;
import kr.co.insoft.core.model.orchestration.ServiceEntityModel;
import kr.co.insoft.core.repository.configration.sev.SEVRepository;
import kr.co.insoft.core.repository.orchestration.OrchestrationRepository;
import kr.co.insoft.core.service.configration.sev.impl.SEVCompute;
import kr.co.insoft.core.service.configration.sev.impl.SevMappingCompute;
import kr.co.insoft.core.service.orchestration.OrchestrationService;
import kr.co.insoft.framework.exceptions.ExceptionCode;
import kr.co.insoft.framework.exceptions.ServiceException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class OrchestrationServiceImpl implements OrchestrationService {

	private static final Logger OrchestrationServiceImplLog = LoggerFactory
			.getLogger(OrchestrationServiceImpl.class);

	@Autowired
	OrchestrationRepository orchestrationRepository;

	@Autowired
	SEVRepository sevRepository;

	@Override
	public ProjectEntityModel getProject(String projectid)
			throws ServiceException {
		try {
			ProjectEntityModel projectEntityModel = new ProjectEntityModel();
			Authentication auths = SecurityContextHolder.getContext()
					.getAuthentication();
			projectEntityModel.setAuth((User) auths.getPrincipal());
			projectEntityModel.setProjectid(projectid);
			projectEntityModel = orchestrationRepository
					.getProject(projectEntityModel);
			SEVCompute compute = null;
			for (SEVEntityModel sev : projectEntityModel.getVariables()) {
				compute = new SEVCompute(sev.getVariables());
				sev.setVariables(compute.getVariablesAsTable());
			}
			return projectEntityModel;
		} catch (Exception e) {
			OrchestrationServiceImplLog.error(ExceptionCode.SERVICE_EXCEPTION,
					e);
			throw new ServiceException(ExceptionCode.SERVICE_EXCEPTION, e);
		}
	}

	@Override
	public ServiceEntityModel createServiceForm(String projectid)
			throws ServiceException {
		try {
			ServiceEntityModel serviceEntityModel = new ServiceEntityModel();
			serviceEntityModel.setProjectid(projectid);
			serviceEntityModel.setProject(getProject(projectid));
			return serviceEntityModel;
		} catch (ServiceException e) {
			OrchestrationServiceImplLog.error(ExceptionCode.SERVICE_EXCEPTION,
					e);
			throw new ServiceException(ExceptionCode.SERVICE_EXCEPTION, e);
		}
	}

	@Override
	@Transactional(rollbackFor = ServiceException.class)
	@CacheEvict("OrchestrationTree")
	public OrchestrationResultModel createProject(
			ProjectEntityModel projectEntityModel) throws ServiceException {
		try {
			Authentication auths = SecurityContextHolder.getContext()
					.getAuthentication();
			projectEntityModel.setAuth((User) auths.getPrincipal());
			OrchestrationResultModel result = orchestrationRepository
					.createProject(projectEntityModel);
			SevMappingCompute compute = new SevMappingCompute(result.getId(),
					projectEntityModel.getVariableTemp());
			if (compute.isExist()) {
				sevRepository.createSEVMapping(compute.getMappings());
			}
			return result;
		} catch (Exception e) {
			OrchestrationServiceImplLog.error(ExceptionCode.SERVICE_EXCEPTION,
					e);
			throw new ServiceException(ExceptionCode.SERVICE_EXCEPTION, e);
		}
	}

	@Override
	@Transactional(rollbackFor = ServiceException.class)
	@CacheEvict("OrchestrationTree")
	public OrchestrationResultModel createService(
			ServiceEntityModel serviceEntityModel) throws ServiceException {
		try {
			Authentication auths = SecurityContextHolder.getContext()
					.getAuthentication();
			serviceEntityModel.setAuth((User) auths.getPrincipal());
			OrchestrationResultModel result = orchestrationRepository
					.createService(serviceEntityModel);
			SevMappingCompute compute = new SevMappingCompute(result.getId(),
					serviceEntityModel.getVariableTemp());
			if (compute.isExist()) {
				sevRepository.createSEVMapping(compute.getMappings());
			}
			return result;
		} catch (Exception e) {
			OrchestrationServiceImplLog.error(ExceptionCode.SERVICE_EXCEPTION,
					e);
			throw new ServiceException(ExceptionCode.SERVICE_EXCEPTION, e);
		}
	}

	@Override
	public ServiceEntityModel getService(String serviceid)
			throws ServiceException {
		try {
			Authentication auths = SecurityContextHolder.getContext()
					.getAuthentication();
			ServiceEntityModel serviceEntityModel = new ServiceEntityModel();
			serviceEntityModel.setAuth((User) auths.getPrincipal());
			serviceEntityModel.setServiceid(serviceid);
			serviceEntityModel = orchestrationRepository
					.getService(serviceEntityModel);
			SEVCompute compute = null;
			for (SEVEntityModel sev : serviceEntityModel.getVariables()) {
				compute = new SEVCompute(sev.getVariables());
				sev.setVariables(compute.getVariablesAsTable());
			}
			return serviceEntityModel;
		} catch (Exception e) {
			OrchestrationServiceImplLog.error(ExceptionCode.SERVICE_EXCEPTION,
					e);
			throw new ServiceException(ExceptionCode.SERVICE_EXCEPTION, e);
		}
	}

	@Override
	public CompositeEntityModel createCompositeForm(String serviceid)
			throws ServiceException {
		try {
			CompositeEntityModel compositeEntityModel = new CompositeEntityModel();
			compositeEntityModel.setServiceid(serviceid);
			compositeEntityModel.setService(getService(serviceid));
			return compositeEntityModel;
		} catch (ServiceException e) {
			OrchestrationServiceImplLog.error(ExceptionCode.SERVICE_EXCEPTION,
					e);
			throw new ServiceException(ExceptionCode.SERVICE_EXCEPTION, e);
		}
	}

	@Override
	public CompositeStackEntityModel createStackForm(String compositeid)
			throws ServiceException {
		try {
			CompositeStackEntityModel stackEntityModel = new CompositeStackEntityModel();
			stackEntityModel.setCompositeid(compositeid);
			stackEntityModel.setComposite(getComposite(compositeid));
			return stackEntityModel;
		} catch (ServiceException e) {
			OrchestrationServiceImplLog.error(ExceptionCode.SERVICE_EXCEPTION,
					e);
			throw new ServiceException(ExceptionCode.SERVICE_EXCEPTION, e);
		}
	}

	@Override
	@Transactional(rollbackFor = ServiceException.class)
	@CacheEvict("OrchestrationTree")
	public OrchestrationResultModel createComposite(
			CompositeEntityModel compositeEntityModel) throws ServiceException {
		try {
			Authentication auths = SecurityContextHolder.getContext()
					.getAuthentication();
			compositeEntityModel.setAuth((User) auths.getPrincipal());
			OrchestrationResultModel result = orchestrationRepository
					.createComposite(compositeEntityModel);
			SevMappingCompute compute = new SevMappingCompute(result.getId(),
					compositeEntityModel.getVariableTemp());
			if (compute.isExist()) {
				sevRepository.createSEVMapping(compute.getMappings());
			}
			return result;
		} catch (Exception e) {
			OrchestrationServiceImplLog.error(ExceptionCode.SERVICE_EXCEPTION,
					e);
			throw new ServiceException(ExceptionCode.SERVICE_EXCEPTION, e);
		}
	}

	@Override
	public CompositeEntityModel getComposite(String compositeid)
			throws ServiceException {
		try {
			Authentication auths = SecurityContextHolder.getContext()
					.getAuthentication();
			CompositeEntityModel compositeEntityModel = new CompositeEntityModel();
			compositeEntityModel.setAuth((User) auths.getPrincipal());
			compositeEntityModel.setCompositeid(compositeid);
			compositeEntityModel = orchestrationRepository
					.getComposite(compositeEntityModel);
			SEVCompute compute = null;
			for (SEVEntityModel sev : compositeEntityModel.getVariables()) {
				compute = new SEVCompute(sev.getVariables());
				sev.setVariables(compute.getVariablesAsTable());
			}
			return orchestrationRepository.getComposite(compositeEntityModel);
		} catch (Exception e) {
			OrchestrationServiceImplLog.error(ExceptionCode.SERVICE_EXCEPTION,
					e);
			throw new ServiceException(ExceptionCode.SERVICE_EXCEPTION, e);
		}
	}

	@Override
	@Transactional(rollbackFor = ServiceException.class)
	@CacheEvict("OrchestrationTree")
	public void removeProject(String projectid) throws ServiceException {
		try {
			ProjectEntityModel projectEntityModel = new ProjectEntityModel();
			projectEntityModel.setProjectid(projectid);
			if (orchestrationRepository
					.getProjectChildCount(projectEntityModel) == 0) {
				sevRepository.removeSEVMapping(projectid);
				orchestrationRepository.removeProject(projectEntityModel);
			} else {
				throw new ServiceException(ExceptionCode.HAVE_CHILD_NOT_DELETE);
			}
		} catch (ServiceException e) {
			throw e;
		} catch (Exception e) {
			OrchestrationServiceImplLog.error(ExceptionCode.SERVICE_EXCEPTION,
					e);
			throw new ServiceException(ExceptionCode.SERVICE_EXCEPTION, e);
		}
	}

	@Override
	public void removeComposite(String compositeid) throws ServiceException {
		try {
			CompositeEntityModel compositeEntityModel = new CompositeEntityModel();
			compositeEntityModel.setCompositeid(compositeid);
			if (orchestrationRepository
					.getChildCountComposite(compositeEntityModel) == 0) {
				sevRepository.removeSEVMapping(compositeid);
				orchestrationRepository.removeComposite(compositeEntityModel);
			} else {
				throw new ServiceException(ExceptionCode.HAVE_CHILD_NOT_DELETE);
			}
		} catch (ServiceException e) {
			throw e;
		} catch (Exception e) {
			OrchestrationServiceImplLog.error(ExceptionCode.SERVICE_EXCEPTION,
					e);
			throw new ServiceException(ExceptionCode.SERVICE_EXCEPTION, e);
		}
	}

	@Override
	public void removeService(String serviceid) throws ServiceException {
		try {
			ServiceEntityModel serviceEntityModel = new ServiceEntityModel();
			serviceEntityModel.setServiceid(serviceid);
			if (orchestrationRepository
					.getChildCountService(serviceEntityModel) == 0) {
				sevRepository.removeSEVMapping(serviceid);
				orchestrationRepository.removeService(serviceEntityModel);
			} else {
				throw new ServiceException(ExceptionCode.HAVE_CHILD_NOT_DELETE);
			}
		} catch (ServiceException e) {
			throw e;
		} catch (Exception e) {
			OrchestrationServiceImplLog.error(ExceptionCode.SERVICE_EXCEPTION,
					e);
			throw new ServiceException(ExceptionCode.SERVICE_EXCEPTION, e);
		}
	}

	@Override
	public OrchestrationResultModel createStack(
			CompositeStackEntityModel compositeStackEntityModel)
			throws ServiceException {
		try {
			Authentication auths = SecurityContextHolder.getContext()
					.getAuthentication();
			compositeStackEntityModel.setAuth((User) auths.getPrincipal());
			return orchestrationRepository
					.createStack(compositeStackEntityModel);
		} catch (Exception e) {
			OrchestrationServiceImplLog.error(ExceptionCode.SERVICE_EXCEPTION,
					e);
			throw new ServiceException(ExceptionCode.SERVICE_EXCEPTION, e);
		}
	}
}
